package cn.edu.zut.sunday.base.controller;

import cn.edu.zut.sunday.base.domain.BaseEntity;
import java.io.Serializable;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;

@Slf4j
public class BaseControllerHandler<T extends BaseEntity<I>, I extends Serializable>
  extends BaseController<T, I> {

    /**
     * 添加一个实体对象时，可以对该实体进行检查或者操作，该方法在@{GenericController#add}调用
     *
     * @param model 前端数据对象
     * @param request http请求，用户可以通过该方法接受格外的自定义参数
     * @return 处理后的对象，如果前端数据不符合要求，则返回null，不会更新数据库。 默认是不做任何检查处理，直接返回model，即直接插入数据到数据库中。
     */
    protected T addModelCheck(T model, HttpServletRequest request) {
        return model;
    }

    /**
     * 修改一个实体对象时，可以对该实体进行检查或者操作，该方法在@{GenericController#update}调用
     *
     * @param id 需改更改的实体对象id
     * @param model 前端数据对象
     * @param request http请求，用户可以通过该方法接受格外的自定义参数
     * @return 处理后的对象，如果前端数据不符合要求，则返回null，不会更新数据库。 默认是不做任何检查处理，直接返回model，即直接使用传过来的数据到修改数据库中数据。
     */
    protected T updateModelCheck(I id, T model, HttpServletRequest request) {
        model.setId(id);
        return model;
    }


    /**
     * 根据接受的参数，创建分页对象，该方法在@{GenericController#getList}调用
     *
     * @param page 当前页数，已经做了-1操作，符合数据库查询，无需操作
     * @param size 一页数据的数量
     * @return 分页对象。默认是按照ID升序进行分页查询操作
     */
    protected Pageable createPageable(int page, int size) {
        Sort sort = Sort.by(Direction.ASC, "id");
        return PageRequest.of(page, size, sort);
    }

    /**
     * 对获取的对象进行格外的操作
     *
     * @param resultPage 从数据库中获取的数据库实体信息
     * @return 返回转换后的实体信息。该方法默认把实体转成Object类型返回
     */
    protected Object transform(Page<T> resultPage) {
        return resultPage;
    }

    /**
     * 对获取的对象进行格外的操作
     *
     * @param entity 从数据库中获取的一个数据库实体信息
     * @return 返回转换后的实体信息。该方法默认把实体转成Object类型返回
     */
    protected Object transform(T entity) {
        return entity;
    }

    /**
     * 根据请求的RequestBody，需要先序列化成需要的对象，方便处理，该方法在@{GenericController#getList}调用
     * 当requestBodyStr为空时，该方法不会被调用
     *
     * @param requestBodyStr 请求的RequestBody字符串对象，需要之类使用序列化工具创建对应对象
     * @return Specification对象，用于高级查询；如果不继承则返回null；默认返回null
     */
    protected Specification<T> createSpecification(String requestBodyStr) {
        return null;
    }

    /**
     * 给实体添加通用属性信息，主要是修改日期，创建日期
     *
     * @param model 实体对象
     * @param created 是否是创建，如果为true，则会设置创建日期，否则只设置修改日期
     * @return 修改后的实体对象
     */
    protected T setCommonAttr(T model, boolean created) {
        final Date date = new Date();
        if (created) {
            model.setDateCreated(date);
        }
        model.setDateModified(date);
        return model;
    }

    /**
     * 处理一个关键字的格式为sql的like格式： "%key%"
     *
     * @param key 具体关键字
     * @return 返回带百分号的关键字字符串："%key%"
     */
    protected String sqlLike(String key) {
        // generate "%key%" format
        return String.format("%%%s%%", key);
    }

}
